﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Minio;
using Niaofei.Domain.Shared;
using Niaofei.EntityFrameworkCore;
using Niaofei.HttpApi;
using Niaofei.Injcetion;
using Niaofei.Web.Authorize;
using System.Reflection;
using System.Text;

namespace Niaofei.Web
{
    public static class Extensions
    {
        /// <summary>
        /// 身份认证配置
        /// </summary>
        public static void AddAuthentication(this IServiceCollection services, ConfigurationManager configuration)
        {
            services.AddAuthorization(options =>
            {
                options.AddPolicy("CustomPolicy", policy =>
                    policy.Requirements.Add(new CustomRequirement()));
            });
            services.AddSingleton<IAuthorizationHandler, CustomHandler>();

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.EventsType = typeof(CustomJwtBearerEvents);

                var authorizationOptions = configuration.GetSection(Domain.Shared.AuthorizationOptions.Options).Get<Domain.Shared.AuthorizationOptions>();
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = authorizationOptions.Issuer,
                    ValidAudience = authorizationOptions.Audience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authorizationOptions.SecretKey))
                };
            });
        }

        /// <summary>
        /// EFCore配置
        /// </summary>
        public static void AddDbContext(this IServiceCollection services, ConfigurationManager configuration)
        {
            services.AddDbContext<NiaofeiDbContext>(option =>
            {
                var version = new MySqlServerVersion(new Version(8, 0, 31));

                option.UseMySql(configuration.GetConnectionString("MySqlConnection"), version, b => b.MigrationsAssembly("Niaofei.Web"));
            });
        }

        /// <summary>
        /// swagger配置
        /// </summary>
        public static void AddSwaggerGen(this IServiceCollection services)
        {
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
                options.SwaggerDoc("v2", new OpenApiInfo { Title = "My API", Version = "v2" });
                var xmlFilenames = APiCommon.GetXmlDocument();

                foreach (var xmlFile in xmlFilenames)
                {
                    options.IncludeXmlComments(xmlFile, true);
                }

                var securityScheme = new OpenApiSecurityScheme()
                {
                    Name = "Authorization",
                    Type = SecuritySchemeType.Http,
                    Scheme = "Bearer",
                    BearerFormat = "JWT",
                    Description = "请输入你的Token",
                    In = ParameterLocation.Header,
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                    }
                };

                options.AddSecurityDefinition("Bearer", securityScheme);

                var securityRequirement = new OpenApiSecurityRequirement()
                {
                    { securityScheme, Array.Empty<string>() }
                };

                options.AddSecurityRequirement(securityRequirement);
            });
        }

        /// <summary>
        /// Api接口Json序列化全局配置
        /// </summary>
        public static void AddControllersAndSetJsonOption(this IServiceCollection services)
        {
            services.AddControllers().AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
            });
        }

        /// <summary>
        /// 通过程序集动态加载服务
        /// </summary>
        public static void LoadAssemblys(this IServiceCollection services)
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            services.InjectionService(assemblies);
        }

        /// <summary>
        /// 跨域问题配置
        /// </summary>
        public static void AddCors(this IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddDefaultPolicy(builder =>
                {
                    builder.AllowAnyOrigin()
                           .AllowAnyMethod()
                           .AllowAnyHeader();
                });
            });
        }

        /// <summary>
        /// Minio服务注入
        /// </summary>
        public static void AddMinio(this IServiceCollection services, ConfigurationManager configuration)
        {
            services.AddScoped(typeof(IMinioClient), provider => 
            {
                var option = provider.GetRequiredService<IOptions<MinioOption>>().Value;

                var client = new MinioClient()
                    .WithEndpoint(option.Endpoint)
                    .WithCredentials(option.AccessKey, option.SecretKey)
                    .WithSSL(option.IsSSL)
                    .Build();

                return client;
            });
        }

        /// <summary>
        /// 日志文件映射访问
        /// </summary>
        public static IApplicationBuilder LogMapper(this IApplicationBuilder app)
        {
            var path = Path.Combine(Directory.GetCurrentDirectory(), "logs");
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            var provider = new FileExtensionContentTypeProvider();
            provider.Mappings[".log"] = "text/plain;charset=utf-8";
            provider.Mappings[".txt"] = "text/plain;charset=utf-8";
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(path),
                ContentTypeProvider = provider,
                DefaultContentType = "application/x-msdownload",
                RequestPath = "/logs"
            });
            app.UseDirectoryBrowser(new DirectoryBrowserOptions
            {
                FileProvider = new PhysicalFileProvider(path),
                RequestPath = "/logs"
            });

            return app;
        }
    }
}
